/**
 * 第一步：
 *      1. promise 接受一个执行器参数，该执行器以一个两个参数resolve, reject
 *        执行器是创建对象立即执行的， 所以执行器实在构造函数里
 * 
 *      2. 状态：三种分别是， 状态字符串， 可以定义成常量, 在
 *               pedding:    等待中  
 *               fulfilled:   成功
 *               rejected:    失败
 *         状态可以从：pedding --> fulfilled, 或者 pedding --> rejected，
 *         状态一旦确定， 就不可在改变
 *      3. 执行器里面的resolve, reject 方法执行时， 就会改变对应的状态的， 状态是需要保存的， 定义保存status
 *                  resolve:  pedding --> fulfilled, 该方法是处理成功的, 
 *                           接受一个成功数据参数value（异步操作的结果）, value是在then 方法的第一个参数（函数参数）里使用的
 *         reject:  pedding -->rejected    该方法是处理失败的
 *                 接受一个失败数据参数reason（异步操作失败的原因）, reason,是在then 方法的第二个参数（函数参数）里使用的
 * 
 *      4. then： 该方法内部判断状态， 如果是成功状态， 就执行成功回调函数(successCallBack)， 如果失败就调用失败回调函数(failCallBack)， 该方法是prosie对象调用， 所以直接定义在原型对象（MyPromisele类）中
 *                successCallBack: 接受一个参数：操作成功之后的值, 分同步，异步操作两种情况
 *                failCallBack： 接受一个参数， 操作失败的原因，  分同步，异步操作两种情况
 *               可以被调用多次, 也就是successCallBack， failCallBack的存储是一个数组
 *              then方法是可以被链式调用的, 后面then方法的回调函数拿到值的是上一个then方法的回调函数的返回值,
 *              回调函数返回值， 不能自己返回自己
 * 
 *  第二步：all : 并行执行
 *         catch
 *         resolve 
 *         catch
 *         finally
 */
const PEDDING = 'pedding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Mypromsie {
    constructor (excutor) {
        excutor(this.resolve, this.reject)  // 接受两个参数分别是  resolve, reject, 在Mypromsie类定义这两个属性
    }
    status = PEDDING // 默认值
    _value = undefined // 保存成功的值
    _reason = undefined // 保存失败的原因
    successCallBack = [] // then 里注册的成功回调函数
    failCallBack = []  // then 里注册的失败回调函数
    resolve = value =>  {    // then 回调函数中会使用value 所以保存起来
        if (!Object.is(this.status, PEDDING)) return   // 状态一旦确定就不可在变化
        this.status = FULFILLED
        this._value = value
        while(this.successCallBack.length) { // 如果存在， 则是异步操作
        //     this.successCallBack(this._value)
            this.successCallBack.shift()() // 传递的函数里含有this.value所以这里不需要了
        }
    }
    reject = reason => {  // then 回调函数中会使用reason 所以保存起来
        if (!Object.is(this.status, PEDDING)) return   // 状态一旦确定就不可在变化
        this.status = REJECTED
        this._reason = reason
        while(this.failCallBack.length) { // 如果存在， 则是异步操作
            this.failCallBack.shift()()
         }
    }
    then(successCallBack, failCallBack) { // 分同步操作， 和异步操作分别处理
        const promise2 = new Promise((resolve, reject) => {  // successCallBack，failCallBack的返回值，promsie2的resolve, reject方法的的参数值一直传递下去 
            if (Object.is(this.status, FULFILLED)) {
                // 这里 promise2 还没有初始化， 所以这里拿不到， 所以这里 使用异步，让其先初始化
                setTimeout(() => { 
                    try {
                        const x = successCallBack(this._value) // 异步操作成功的值， 传给成功回调, 同步操作情况下, 同步情况下， 回调函数直接执行， 不需要存储到数组
                        resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值， 被传递到resolve方法中
                    } catch (e) { // 捕获异常， 执行reject
                        reject(e)
                     }
                }, 0)
            } else if (Object.is(this.status, REJECTED)) {
                setTimeout(() => { 
                    try {
                        const x = failCallBack(this._reason)  // 异步操作失败的值， 传给失败回调， 同步操作情况下，同步情况下， 回调函数直接执行， 不需要存储到数组
                        resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值， 被传递到resolve方法中
                    } catch (e) { // 捕获异常， 执行reject
                        reject(e)
                     }
                }, 0)
                if (successCallBack) {  
                    this.successCallBack.push(() => { 
                        setTimeout(() => {
                            try {
                                const x = successCallBack(this._value)
                                resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值， 被传递到resolve方法中
                            } catch (e) { // 捕获异常， 执行reject
                                reject(e)
                             }
                         }, 0)
                    }) // 这里不能像上面的successCallBack那样直接获取返回值（因为状态还没有该拜年）， 利用高阶函数，返回一个函数，就行
                }
                if (failCallBack) { 
                    this.failCallBack.push(() => { 
                        setTimeout(() => {
                            try {
                                const x = failCallBack(this._reason)
                                resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值， 被传递到resolve方法中
                            } catch (e) { // 捕获异常， 执行reject
                                reject(e)
                             }
                         }, 0)
                    })
                }
            }
        })
        return promise2 // 返回promise以实现then 的链式调用
    }
    // 捕获整个promise链的异常
    catch(failCallBack) {
        return this.then(undefined, failCallBack)
    }
    /**
     * @param {*} callback
     * @memberof Mypromsie
     * 不管是成功，还是失败都会执行这个方法
     */
    finally(callback) { 
        return this.then(value => {
            return new Mypromsie.resolve(callback()).then(() => value)
        }, reason => { 
                return new Promise.resolve(callback()).then(() => { 
                    throw reason
                })
        })
    } 
    /**
     * @static
     * @param {*} array promise 数组
     * @memberof Mypromsie
     * @return  返回的也是一个promise
     * 数组的promise必须全部完成， 这个promise才完成
     */
    static all(array) {
        let result = [] // promise 的执行结果
        let index = 0  // 第几个promsie
        return new Mypromsie((resolve, reject) => { 
            // 把promise的处理结果， 添加进数组
            function addData(_index, data) {
                result[_index, data] // promise 的执行期可能不是同步的， 所以不能使用Push
                ++index 
                if (result.length === index) { // 数组的长度和inde长度一致吗， 说明所有promise 都执行完成了
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i]
                if (current instanceof Mypromsie) {
                    // Mypromise 对象
                    current.then(value => {
                        addData(i, value) // 添加
                    }, reason => {
                        reject(reason) // 整个promise 结束
                    })
                } else { // 普通值， 直接添加
                    addData(i, current)
                }
            }
        })
    }
    /**
     * @static
     * @param {*} value
     * @returns
     * @memberof Mypromsie
     * 如果是promise 就直接返回
     * 如果是普通对象， 则包裹成promsie 
     */
    static resolve(value) {
        if (value instanceof Mypromsie) return value
        return new Mypromsie(resolve => resolve(value))
     }
}
/**
     *
     *
     * @param {*} 调用的promise
     * @param {*} 返回的值
     * @param {*} resolve
     * @param {*} reject
     * @return 
     * @memberof Mypromsie
     * 如果是普通值 直接调用resolve 
     * 如果是promise对象 查看promsie对象返回的结果 
     * 再根据promise对象返回的结果 决定调用resolve 还是调用reject
     */
    function resolvePromise(promise, x, resolve, reject) { 
        if (promise === x) { // 防止自己返回自己， 造成死循环 
            return reject(new Error('Chaining cycle detected for promise #<Promise>'))
        }
        //then 返回的是 promise 对象
        // 则 返回x.then(valuie => resolve(x), reason => reject(reason))
        if (x instanceof Mypromsie) {
            x.then(resolve, reject) // 简写
        } else { 
            resolve(x) // 普通值
        }
    }
module.exports = Mypromsie // 导出